import { InjectionKey, Ref, defineComponent, ref, provide, inject, computed } from 'vue';
import { computedInject } from '@vueuse/core';

type OptionsRef = Ref<{ key: number; value: string }[]>;
export const ArrayKey: InjectionKey<OptionsRef> = Symbol('array');

type CountKeyType = InjectionKey<Ref<number>>;
const countKey: CountKeyType = Symbol('array');

const Child = defineComponent({
  setup() {
    const computedArr = computedInject(ArrayKey, source => {
      if (!source) return ref([]) as OptionsRef;
      const arr = [...source.value];
      arr.unshift({ key: 0, value: 'all' });
      return arr;
    });

    const count = ref(0);

    // 想把把project提供的值在子组件中做成响应式的 前提是provide提供的值是一个响应式对象
    const injectCount = inject('computedInjectCount') as Ref<any>;
    const computedInjectCount = computed(() => injectCount.value);

    /**
     * 需要注意的是 既然传递的值是响应式的 为什么不知道使用injectCount而是又用computed包裹一次变成computedInjectCount？
     * 因为 provide提供的数据只是用来访问的，子组件没有权限去修改至上而下传递过来的数据，数据的修改应该由提供者来修改，
     * 如果直接修改，违背框架的思想，也不能这么做，不然数据传递的顺序就乱套了
     *
     * 使用computed包裹相当于变成了只读属性，避免误操作数据 而computedInject这个方式帮我我们省去了自己包装computed和调用inject方法，直接一步即可使用
     */

    const injectCount2 = computedInject(countKey, source => source?.value);

    return () => {
      return (
        <>
          <p>
            count：{count.value}
            <br />
            computedInjectCount：{injectCount.value}
            <br />
            computedInjectCount：{computedInjectCount.value}
            <br />
            injectCount2：{injectCount2.value}
            <br />
            <button onClick={() => count.value++}>修改count</button>
            <br />
            <button onClick={() => injectCount.value++}>修改injectCount</button>
          </p>
          <div>ComputedArr: {JSON.stringify(computedArr.value)}</div>
        </>
      );
    };
  },
});

export default defineComponent({
  setup() {
    const array = ref([
      { key: 1, value: '1' },
      { key: 2, value: '2' },
      { key: 3, value: '3' },
    ]);

    provide(ArrayKey, array);

    const count = ref(0);
    provide('computedInjectCount', count);

    const count2 = ref(10);
    provide(countKey, count2);

    return () => {
      return (
        <div>
          父亲：
          <p>不用vueuse提供的方法，让依赖注入的值实现响应式更新</p>
          <p>
            count：{count.value}
            <br />
            count2：{count2.value}
            <br />
            <button onClick={() => count.value++}>修改count</button>
            <br />
            <button onClick={() => count2.value++}>修改count2</button>
            <br />
            <p>Array: {JSON.stringify(array.value)}</p>
          </p>
          <hr />
          <div>
            儿子：
            <Child />
          </div>
        </div>
      );
    };
  },
});
